﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ImageZoomCtrl
{

    [TemplatePart(Name = ElementImageMain, Type = typeof(Image))]
    [TemplatePart(Name = ElementContentControlMain, Type = typeof(ContentControl))]
    public class ImageFrameCtrl : Control
    {
        public const string ElementImageMain = "IMG1";

        public const string ElementContentControlMain = "ContentControlMain";


        Image _image;
        ContentControl _contentControl;
        static ImageFrameCtrl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageFrameCtrl), new FrameworkPropertyMetadata(typeof(ImageFrameCtrl)));
        }
        private bool mouseDown;
        private Point mouseXY;

        public ImageFrameCtrl()
        {
            Loaded += (s, e) =>
            {
                if (_contentControl != null)
                {
                    _contentControl.MouseLeftButtonDown -= ContentControl_MouseLeftButtonDown;
                    _contentControl.MouseLeftButtonUp -= ContentControl_MouseLeftButtonUp;
                    _contentControl.MouseMove -= ContentControl_MouseMove;
                    _contentControl.MouseWheel -= ContentControl_MouseWheel;
                }

                _image = GetTemplateChild(ElementImageMain) as Image;
                if (_image != null)
                {
                    _image.RenderTransform = CreateTransformGroup();
                }
                _contentControl = GetTemplateChild(ElementContentControlMain) as ContentControl;
                if (_contentControl != null)
                {
                    _contentControl.MouseLeftButtonDown += ContentControl_MouseLeftButtonDown;
                    _contentControl.MouseLeftButtonUp += ContentControl_MouseLeftButtonUp;
                    _contentControl.MouseMove += ContentControl_MouseMove;
                    _contentControl.MouseWheel += ContentControl_MouseWheel;
                }
            };
        }

        private Transform CreateTransformGroup()
        {
            TransformGroup transformGroup = new TransformGroup();
            ScaleTransform scaleTransform = new ScaleTransform();
            TranslateTransform translateTransform = new TranslateTransform();
            transformGroup.Children.Add(scaleTransform);
            transformGroup.Children.Add(translateTransform);
            return transformGroup;
        }

        public readonly static DependencyProperty VideoImageSourceProperty = DependencyProperty.Register(nameof(VideoImageSource), typeof(ImageSource), typeof(ImageFrameCtrl));

        public ImageSource VideoImageSource
        {
            get => (ImageSource)GetValue(VideoImageSourceProperty);
            set => SetValue(VideoImageSourceProperty, value);

        }

        #region Event
        //鼠标按下时的事件，启用捕获鼠标位置并把坐标赋值给mouseXY.
        private void ContentControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            img.CaptureMouse();
            mouseDown = true;
            mouseXY = e.GetPosition(img);
        }

        //鼠标松开时的事件，停止捕获鼠标位置。
        private void ContentControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            img.ReleaseMouseCapture();
            mouseDown = false;
        }

        //鼠标移动时的事件，当鼠标按下并移动时发生Domousemove(img, e);函数 
        private void ContentControl_MouseMove(object sender, MouseEventArgs e)
        {
            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            if (mouseDown)
            {
                Domousemove(img, e);
            }
        }

        //group.Children中的第二个是移动的函数
        //它根据X.Y的值来移动。并把当前鼠标位置赋值给mouseXY.
        private void Domousemove(ContentControl img, MouseEventArgs e)
        {
            if (e.LeftButton != MouseButtonState.Pressed)
            {
                return;
            }

            var group = _image.RenderTransform as TransformGroup;
            var transform = group.Children[1] as TranslateTransform;
            var scaleTransform = group.Children[0] as ScaleTransform;
            var position = e.GetPosition(img);
            transform.X -= (mouseXY.X - position.X);
            transform.Y -= (mouseXY.Y - position.Y);
            var transformArea = new Point(-img.ActualWidth * (scaleTransform.ScaleX - 1), -img.ActualHeight * (scaleTransform.ScaleY - 1));
            //往右与往下移动禁止超出
            if (mouseXY.X - position.X < 0 && transform.X > 0)
                transform.X = 0;
            if (mouseXY.Y - position.Y < 0 && transform.Y > 0)
                transform.Y = 0;
            // 往左与往上移动禁止超出
            if (mouseXY.X - position.X > 0 && transform.X < transformArea.X)
                transform.X = transformArea.X;
            if (mouseXY.Y - position.Y > 0 && transform.Y < transformArea.Y)
                transform.Y = transformArea.Y;

            mouseXY = position;

        }

        //鼠标滑轮事件，得到坐标，放缩函数和滑轮指数，由于滑轮值变化较大所以*0.001.
        private void ContentControl_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            var img = sender as ContentControl;
            if (img == null)
            {
                return;
            }
            var point = e.GetPosition(img);
            var group = _image.RenderTransform as TransformGroup;
            var delta = e.Delta * 0.001;
            DowheelZoom(group, point, delta);
        }
        //Group.Children中的第一个是放缩函数。
        //如果ScaleX+滑轮指数小于0.1时就返回。
        //var pointToContent = group.Inverse.Transform(point);
        //获取此变换的逆变换的值
        //使图片放缩后，放缩原点也随之变化。
        private void DowheelZoom(TransformGroup group, Point point, double delta)
        {
            var pointToContent = group.Inverse.Transform(point);
            var scaleTransform = group.Children[0] as ScaleTransform;
            if (scaleTransform.ScaleX + delta < 0.1) return;
            scaleTransform.ScaleX += delta;
            scaleTransform.ScaleY += delta;

            if (scaleTransform.ScaleX < 1)
                scaleTransform.ScaleX = 1;
            if (scaleTransform.ScaleY < 1)
                scaleTransform.ScaleY = 1;

            var transform1 = group.Children[1] as TranslateTransform;
            transform1.X = -1 * ((pointToContent.X * scaleTransform.ScaleX) - point.X);
            transform1.Y = -1 * ((pointToContent.Y * scaleTransform.ScaleY) - point.Y);
            if (transform1.X > 0)
                transform1.X = 0;
            if (transform1.Y > 0)
                transform1.Y = 0;


        }
        #endregion
    }
}
